from pacs.models import Goal,GoalResults,Task,TaskResults,Contest,ContestResults,Submission,TestResults
from django.db.models import datetime
from goal_scoring import goalScoringWays
from datetime import datetime

def update_contest(contest):
	"""Recalculates points for contest"""
	#calculates points
	points = 0
	for task in contest.tasks.all():
		points += task.maxPoints
	
	#saves it
	contest.maxPoints = points
	contest.save()

def update_task(task):
	"""Recalculates points for task and updates contests connected with them"""
	#calculates points
	points = 0
	for goal in task.goal_set.all():
		points += goal.maxPoints

	#saves it
	task.maxPoints = points
	task.save()

	#update contests
	for contest in task.contest_set.all():
		update_contest(contest)

def update_goals():
	"""Searches for goals, that are not published, but their resultTime is later than now, publish them, and update tasks connected with them"""

	#choose goals to publish
	toInclude = Goal.objects.filter(resultsTime__lte=datetime.now(),published=False)

	for it in toInclude:
		#publish them
		it.published =True
		it.save()

		#update task
		update_task(it.task)

def update_contest_results(contest,user):
	"""Updates stored info for user contest results"""

	#get contest results, if no, create it
	try:
		contestResults = ContestResults.objects.get(contest=contest,user=user)
	except ContestResults.DoesNotExist:
		contestResults = ContestResults(contest=contest,user=user)
	
	#calculate results
	bestPoints = lastPoints = 0
	for task in contest.tasks.all():
		try:
			res = TaskResults.objects.get(user=user,task=task)
			lastPoints += res.lastPoints
			bestPoints += res.bestPoints
		except TaskResults.DoesNotExist:
			pass

	#save 'em
	contestResults.lastPoints = lastPoints
	contestResults.bestPoints = bestPoints
	contestResults.save()

def update_task_results(user,task):
	"""Updates stored info for user task results. Updates contests with this task"""

	#get task results, if no, create it
	try:
		taskResults = TaskResults.objects.get(task=task,user=user)
	except TaskResults.DoesNotExist:
		taskResults = TaskResults(task=task,user=user)

	#get results and save
	taskResults.lastPoints = Submission.objects.filter(user=user,task=task).order_by('insertTime')[0].points
	taskResults.bestPoints = Submission.objects.filter(user=user,task=task).order_by('points')[0].points
	taskResults.save()

	#update contests
	for contest in task.contest_set.all():
		update_contest_results(contest,user)

def update_submission(submission):
	"""Updates submission results. Updates tasks connected with it"""

	#calculates points
	points = 0
	submission.status = 0
	for goalResult in submission.goalresults_set.all():
		#one test not checked, run away
		if goalResult.status == 10:
			submission.status = 10
			submission.save()
			return
		if goalResult.status != 0 and submission.status == 0:
			submission.status = goalResult.status
		points += goalResult.points
	
	#save points
	submission.points = points
	submission.checked = True
	submission.save()

	#update tasks results
	update_task_results(submission.user,submission.task)

def update_goals_results():
	"""Searches for goals results, that are not checked, but should be (the goal is published), and updates task results"""

	#choose goals results to mark as checked
	toInclude = GoalResults.objects.filter(goal__published = True,status=10)

	for it in toInclude:
		#iterates on goal tests
		res = []
		for test in it.goal.tests.all():
			try:
				testResults = TestResults.objects.get(submission=it.submission,test=test)
				res.append((testResults.status,testResults.time,test.maxTime))
			except TestResults.DoesNotExist:
				break
		#if test was not found
		else:
			it.points = int(goalScoringWays[it.goal.scoringWay](res)*it.goal.maxPoints)
			for i,r in enumerate(res):
				if r[0] != 0:
					it.status = r[0]
					it.firstFail = i
					break
			else:
				it.status = 0
			it.save()
			update_submission(it.submission)
